﻿using LServer.Core.Utils;
using Microsoft.VisualBasic;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LServer.Core.Logger
{
    public class LoggerMgr
    {
        private static object lock_obj = new object();

        /// <summary>
        /// 日志队列
        /// </summary>
        private static Queue<LoggerEntity> m_LoggerQueue;

        /// <summary>
        /// 日志临时列表
        /// </summary>
        private static List<LoggerEntity> m_LoggerList;

        /// <summary>
        /// 上次保存时间
        /// </summary>
        private static DateTime m_PrevSaveTime;

        /// <summary>
        /// 保存策略
        /// </summary>
        private static LinkedList<LoggerTactics> m_LoggerTactics;

        /// <summary>
        /// 初始化
        /// </summary>
        public static void Init() 
        {
            m_PrevSaveTime = DateTime.UtcNow;
            m_LoggerQueue = new Queue<LoggerEntity> ();
            m_LoggerList = new List<LoggerEntity> ();
            m_LoggerTactics = new LinkedList<LoggerTactics> ();

            //队列里 》= 1000 条 立即写入
            m_LoggerTactics.AddLast(new LoggerTactics() { Count = 1000, Interval = 0 });

            //队列里 》= 100 条 或者距离上次写入 》= 60秒 写入
            m_LoggerTactics.AddLast(new LoggerTactics() { Count = 100, Interval = 60 });

            //队列里》=1条 或者距离上次写入 》=300秒 写入
            m_LoggerTactics.AddLast(new LoggerTactics() { Count = 1, Interval = 300 });
        }

        #region CurrClient
        private static MongoClient m_CurrClient = null;

        /// <summary>
        /// 当前的 MongoClient
        /// </summary>
        public static MongoClient CurrClient
        {
            get
            {
                if (m_CurrClient == null)
                {
                    lock (lock_obj)
                    {
                        if (m_CurrClient == null)
                        {
                            m_CurrClient = new MongoClient("mongodb://127.0.0.1");
                        }
                    }
                }
                return m_CurrClient;
            }
        }

        #endregion

        #region LoggerDBModel
        private static LoggerDBModel m_LoggerDBModel;

        public static LoggerDBModel LoggerDBModel
        {
            get
            {
                if (m_LoggerDBModel == null)
                {
                    lock (lock_obj)
                    {
                        if (m_LoggerDBModel == null)
                        {
                            m_LoggerDBModel = new LoggerDBModel();
                        }
                    }
                }
                return m_LoggerDBModel;
            }
        }
        #endregion

        #region LoggerDBModel
        private static UniqueIDLogger m_UniqueIDLogger;

        public static UniqueIDLogger UniqueIDLogger
        {
            get
            {
                if (m_UniqueIDLogger == null)
                {
                    lock (lock_obj)
                    {
                        if (m_UniqueIDLogger == null)
                        {
                            m_UniqueIDLogger = new UniqueIDLogger();
                        }
                    }
                }
                return m_UniqueIDLogger;
            }
        }
        #endregion

        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="level"></param>
        /// <param name="Category"></param>
        /// <param name="message"></param>
        /// <param name="arges"></param>
        public static void AddLog(LoggerLevel level = LoggerLevel.Log, int category = 0, bool async = true, string message = null, params object[] args)
        {
            LoggerEntity loggerEntity = new LoggerEntity();
            loggerEntity.LFId = UniqueIDLogger.GetUniqueID(category);
            loggerEntity.Level = level;
            loggerEntity.Category = category;
            loggerEntity.Message = args.Length == 0 ? message : string.Format(message, args);
            loggerEntity.CreateTime = loggerEntity.UpdateTime = DateTime.UtcNow;

            Console.WriteLine(string.Format("{0} {1} {2}", loggerEntity.Level, loggerEntity.Category, loggerEntity.Message));

            if (async)
            {
                LoggerDBModel.AddAsync(loggerEntity);
            }
            else 
            {
                LoggerDBModel.Add(loggerEntity);
            }
        }

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="level"></param>
        /// <param name="category"></param>
        /// <param name="message"></param>
        /// <param name="args"></param>
        public static void Log(LoggerLevel level = LoggerLevel.Log, int category = 0, string message = null, params object[] args) 
        {
            Log(level,category,true,message,args);
        }

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="level"></param>
        /// <param name="category"></param>
        /// <param name="async"></param>
        /// <param name="message"></param>
        /// <param name="args"></param>
        public static void Log(LoggerLevel level = LoggerLevel.Log, int category = 0, bool async = true, string message = null, params object[] args)
        {
            LoggerEntity loggerEntity = new LoggerEntity();
            loggerEntity.LFId= UniqueIDLogger.GetUniqueID(category);
            loggerEntity.Level = level;
            loggerEntity.Category = category;
            loggerEntity.Message = message;
            loggerEntity.CreateTime = loggerEntity.UpdateTime = DateTime.UtcNow;

            Console.WriteLine(string.Format("{0} {1} {2}", loggerEntity.Level, loggerEntity.Category, loggerEntity.Message));

            m_LoggerQueue.Enqueue(loggerEntity);

            lock (lock_obj) 
            {
                if (CheckCanSave()) 
                {
                    m_LoggerList.Clear();

                    while (m_LoggerQueue.Count > 0)
                    {
                        m_LoggerList.Add(m_LoggerQueue.Dequeue());
                    }

                    if (async)
                    {
                        LoggerDBModel.AddManyAsync(m_LoggerList);
                    }
                    else 
                    {
                        LoggerDBModel.AddMany(m_LoggerList);
                    }
                    m_PrevSaveTime = DateTime.UtcNow;
                    Console.WriteLine("Logger写入DB完毕");
                }
            }
        }

        #region SaveDBWithStopServer 停服的时候写入 DB
        /// <summary>
        /// 停服的时候写入 DB
        /// </summary>
        public static void SaveDBWithStopServer() 
        {
            m_LoggerList.Clear();

            while (m_LoggerQueue.Count > 0) 
            {
                m_LoggerList.Add(m_LoggerQueue.Dequeue());
            }

            LoggerDBModel.AddMany(m_LoggerList);

            m_PrevSaveTime = DateTime.UtcNow; 
            Console.WriteLine("Logger 停服写入DB 完毕");
        }
        #endregion

        #region CheckCanSave 检查是否可以写入 DB
        /// <summary>
        /// 检查是否可以写入 DB
        /// </summary>
        public static bool CheckCanSave()
        {
            LinkedListNode<LoggerTactics> curr = m_LoggerTactics.First;
            while (curr != null) 
            {
                LoggerTactics loggerTactics = curr.Value;
                long invertal = LFDateTimeUtil.GetTimestamp(DateTime.UtcNow) - LFDateTimeUtil.GetTimestamp(m_PrevSaveTime);
                if ( m_LoggerQueue.Count >= loggerTactics.Count && invertal >= loggerTactics.Interval * 1000)
                {
                    return true;
                }
                curr = curr.Next;
            }
            return false;

        }
        #endregion
    }
}
